package symbol;

import lexical.Word;
import midcode.MidcodeGenerator;

import java.util.ArrayList;
import java.util.Objects;

public class Symbol {
    private final int id;
    public String type;
    public Word word;
    public int dim;
    private Integer val_0;
    private int len_1;
    private ArrayList<Integer> val_1;
    private int len_2;
    private ArrayList<ArrayList<Integer>> val_2;

    private int size;
    private int offset_gp;
    private int offset_sp;

    public Symbol(String type, int dim, Word word, int id) {
        this.type = type;
        this.dim = dim;
        this.word = word;
        this.id = id;
    }

    public String getName() {
        if (Objects.equals(type, "tmp")) {
            return word.word;
        }
        return word.word + "_" + word.lineNum + "_" + id;
    }

    public int getValType() {
        if (dim == 0 && val_0 != null) {
            return 0;
        } else if (dim == 1 && val_1 != null) {
            return 1;
        } else if (dim == 2 && val_2 != null) {
            return 2;
        } else {
            return -1;
        }
    }

    public int getVal_0() {
        return val_0;
    }

    public void setVal_0(int val_0) {
        this.val_0 = val_0;
    }

    public ArrayList<Integer> getVal_1() {
        return val_1;
    }

    public void setVal_1(ArrayList<Integer> val_1) {
        this.val_1 = val_1;
        this.len_1 = val_1.size();
    }

    public ArrayList<ArrayList<Integer>> getVal_2() {
        return val_2;
    }

    public void setVal_2(ArrayList<ArrayList<Integer>> val_2) {
        this.val_2 = val_2;
        this.len_1 = val_2.size();
        this.len_2 = val_2.get(0).size();
    }

    public void setLen_1(int len_1) {
        this.len_1 = len_1;
    }

    public int getLen_1() {
        return len_1;
    }

    public void setLen_2(int len_2) {
        this.len_2 = len_2;
    }

    public int getLen_2() {
        return len_2;
    }

    public int getOffset_gp() {
        return offset_gp;
    }

    public void setOffset_gp() {
        MidcodeGenerator mg = MidcodeGenerator.getInstance();
        this.offset_gp = mg.getOffset_gp();
        mg.addOffset_gp(size);
    }

    public int getOffset_sp() {
        return offset_sp + MidcodeGenerator.getInstance().getStackSize();
    }

    public void setOffset_sp() {
        MidcodeGenerator mg = MidcodeGenerator.getInstance();
        this.offset_sp = mg.getOffset_sp();
        mg.addOffset_sp(size);
    }

    public void setSize() {
        if (Objects.equals(type, "tmp") || Objects.equals(type, "param")) {
            size = 4;
        } else {
            if (len_1 == 0) {
                size = 4;
            } else if (len_2 == 0) {
                size = len_1 * 4;
            } else {
                size = len_1 * len_2 * 4;
            }
        }
    }

    public int getSize() {
        return size;
    }

    public ArrayList<Integer> getFlatArray() {
        ArrayList<Integer> flatArray = new ArrayList<>();
        if (dim == 0) {
            if (val_0 == null) {
                val_0 = 0;
            }
            flatArray.add(val_0);
            return flatArray;
        } else if (dim == 1) {
            if (val_1 == null) {
                val_1 = new ArrayList<>();
                for (int i = 0; i < len_1; i++) {
                    val_1.add(0);
                }
            }
            return val_1;
        } else {
            assert dim == 2;
            if (val_2 == null) {
                flatArray = new ArrayList<>();
                for (int i = 0; i < len_1 * len_2; i++) {
                    flatArray.add(0);
                }
            } else {
                for (ArrayList<Integer> val : val_2) {
                    flatArray.addAll(val);
                }
            }
            return flatArray;
        }
    }
}
